package controllers

/** Created by yz on 2017/5/31.
  */

import command.CommandExec
import dao._
import implicits.Implicits._
import play.api.mvc._
import shared.Pojo.{GetHTissueBoxplotImage, GetImageResponse}
import shared.tsPojo.TsPojo
import tool.Pojo.CommandData
import tool.{FormTool, Tool}
import utils.Utils

import java.io.File
import javax.inject.Inject
import scala.concurrent.ExecutionContext.Implicits.global
import ujson.play.PlayJson
import upickle.default._

import scala.collection.immutable.SeqMap

class BrowseGeneController @Inject() (cc: ControllerComponents)(
    implicit val browseGeneDao: BrowseGeneDao,
    implicit val hTissueDataDao: HTissueDataDao,
    implicit val modeDao: ModeDao,
    implicit val mTissueDataDao: MTissueDataDao,
    implicit val boxplotDataDao: BoxplotDataDao,
    implicit val geneExpDao: GeneExpDao,
    implicit val cellLineExprDao: CellLineExprDao
) extends AbstractController(cc) {

  import TsPojo.browseGene._

  def all = Action.async { implicit request =>
    browseGeneDao.selectAll.map { x =>
      val array = Utils.getArrayByTs(x)
      Ok(writeJs(array))
    }
  }

  def allByServer = Action.async { implicit request =>
    val obj = PlayJson.transform(request.body.asJson.get, reader[ujson.Obj])
    val pageData = FormTool.pageForm.bindFromRequest().get
    browseGeneDao.selectAll(obj.value, pageData).map { case (size, x) =>
      val array = Utils.getJsonByTs(x)
      Ok(ujson.Obj("rows" -> array, "total" -> size))
    }
  }

  def getSelect2Values = Action.async { implicit request =>
    val data = FormTool.keysForm.bindFromRequest().get
    browseGeneDao.selectUniqueValues(data.keys).map { valuess =>
      val vMap = data.keys.zip(valuess).toSeqMap
      Ok(writeJs(vMap))
    }
  }

  def hTissueBoxplotImage = Action.async { implicit request =>
    val startTime = System.currentTimeMillis()
    val data = PlayJson.transform(request.body.asJson.get, reader[HTissueBoxplotImage.Request])
    val geneSymbol = data.geneName
    hTissueDataDao.selectAll(geneSymbol).map { rows =>
      val tmpDir = Tool.createTempDirectory("tmpDir")
      val pngFile = new File(tmpDir, "out.png")
      val inputFile = new File(tmpDir, "input.csv")
      val maps = rows.map { row =>
        SeqMap("gene" -> row.gene) ++ Tool.json2SeqMap(row.value)
      }.toList
      maps.csvLines.toFile(inputFile)
      val metaFile = new File(Tool.dataDir, "hbulk_meta.txt")
      val colorFile = new File(Tool.dataDir, "boxplot_pal.txt")
      val command =
        s"""
           |${"Rscript"
            .condaPath()} ${Tool.rPath.unixPath}/hbulk_expr.R --i ${inputFile.unixPath} --m ${metaFile.unixPath} --c ${colorFile.unixPath} --g ${data.group} --p "${data.phenotypes
            .mkString(";")}" --d "${data.datasets.mkString(";")}" --l ${data.log} --o ${pngFile.unixPath}
           |""".stripMargin
      val commandExec = CommandExec().exec { b =>
        CommandData(tmpDir, command)
      }
      val response = if (commandExec.isSuccess) {
        println("exec complete:", Utils.getTime(startTime))
        val base64 = pngFile.base64
        val geneData = new File(tmpDir, "gene.csv").str
        HTissueBoxplotImage.Response(valid = true, base64 = base64, geneData = geneData)
      } else {
        HTissueBoxplotImage.Response(valid = false, message = commandExec.errorInfo)
      }
      Tool.deleteDirectory(tmpDir)
      Ok(writeJs(response))
    }

  }

  def mTissueBoxplotImage = Action.async { implicit request =>
    val startTime = System.currentTimeMillis()
    val data = PlayJson.transform(request.body.asJson.get, reader[MTissueBoxplotImage.Request])
    val geneSymbol = data.geneName
    mTissueDataDao.selectAll(geneSymbol).map { rows =>
      val tmpDir = Tool.createTempDirectory("tmpDir")
      val pngFile = new File(tmpDir, "mbulk_expr_default.png")
      val inputFile = new File(tmpDir, "input.csv")
      val maps = rows.map { row =>
        SeqMap("gene" -> row.gene) ++ Tool.json2SeqMap(row.value)
      }.toList
      maps.csvLines.toFile(inputFile)
      val metaFile = new File(Tool.dataDir, "mbulk_meta.txt")
      val colorFile = new File(Tool.dataDir, "boxplot_pal.txt")
      val command =
        s"""
           |${"Rscript"
            .condaPath()} ${Tool.rPath.unixPath}/mbulk_expr.R --i ${inputFile.unixPath} --m ${metaFile.unixPath} --c ${colorFile.unixPath} --g ${data.group} --p "${data.phenotypes
            .mkString(";")}" --d "${data.datasets.mkString(";")}" --model "${data.models
            .mkString("@@@")}" --l ${data.log}  --o ${pngFile.unixPath}
           |""".stripMargin
      val commandExec = CommandExec().exec { b =>
        CommandData(tmpDir, command)
      }
      val response = if (commandExec.isSuccess) {
        println("exec complete:", Utils.getTime(startTime))
        val base64 = pngFile.base64
        val geneData = new File(tmpDir, "gene.csv").str
        MTissueBoxplotImage.Response(valid = true, base64 = base64, geneData = geneData)
      } else {
        MTissueBoxplotImage.Response(valid = false, message = commandExec.errorInfo)
      }
      println(tmpDir.unixPath)
      Tool.deleteDirectory(tmpDir)
      Ok(writeJs(response))
    }

  }

  def boxplotData = Action.async { implicit request =>
    val data = PlayJson.transform(request.body.asJson.get, reader[BoxplotData.Request])
    boxplotDataDao.selectAll(data.geneName, data.phenotype).map { rows =>
      Ok(writeJs(rows))
    }

  }

  def geneExp = Action.async { implicit request =>
    val data = PlayJson.transform(request.body.asJson.get, reader[BoxplotData.Request])
    geneExpDao.selectAll(data.geneName, data.phenotype).map { x =>
      val array = Utils.getArrayByTs(x)
      Ok(writeJs(array))
    }
  }

  def barData = Action { implicit request =>
    val queryMap = request.queryString.map { case (k, v) =>
      (k, v.head)
    }
    val data = writeJs(queryMap).transform(reader[BarData.Request])
    val file = new File(Tool.dataDir, "Barplot_source.xlsx")
    val lines = file.xlsxLines()
    val maps = lines.lineSeqMap.map { map =>
      val columnSuffix = data.phenotype match {
        case "Viral Hepatitis" => s"_Viral_Hepatitis"
        case "FibCs" => s"_Cirrhosis"
        case x => s"_${x}"
      }
      val freq = map(s"Freq${columnSuffix}")
      val freqStr = if (freq.isDouble) {
        freq.toDouble.toFixed(3)
      } else freq
      SeqMap("celltype" -> map("Cell_Type"), "Freq" -> freqStr)
    }
    val json = writeJs(maps)
    Ok(json)
  }

  def cellType = Action { implicit request =>
    val queryMap = request.queryString.map { case (k, v) =>
      (k, v.head)
    }
    val data = writeJs(queryMap).transform(reader[PhenotypeData])
    val file = new File(Tool.dataDir, "Cell_Type.xlsx")
    val lines = file.xlsxLines()
    val maps = lines.lineSeqMap.map { map =>
      val columnSuffix = data.phenotype match {
        case "FibCs" => s"_Cirrhosis"
        case "Viral Hepatitis" => s"_Viral_Hepatitis"
        case x => s"_${x}"
      }
      val freq = map(s"Freq${columnSuffix}")
      val freqStr = if (freq.isDouble) {
        freq.toDouble.toFixed(3)
      } else freq
      SeqMap(
        "cellType" -> map("Cell_Type"),
        "featureGenes" -> map("Feature_Genes"),
        "freq" -> freqStr,
        "lineage" -> map("Lineage"),
        "clusterResolution" -> map("Cluster_Resolution"),
        "suggestedLabels" -> map("Suggested_Labels")
      )
    }
    val json = writeJs(maps)
    Ok(json)
  }

  def cellLineImage = Action.async { implicit request =>
    val startTime = System.currentTimeMillis()
    val data = PlayJson.transform(request.body.asJson.get, reader[CellLineImage.Request])
    val geneSymbol = data.geneName
    cellLineExprDao.selectAll(geneSymbol).map { rows =>
      val tmpDir = Tool.createTempDirectory("tmpDir")
      val pngFile = new File(tmpDir, "out.png")
      val inputFile = new File(tmpDir, "input.csv")
      val maps = rows.map { row =>
        SeqMap("gene" -> row.gene) ++ Tool.json2SeqMap(row.value)
      }.toList
      maps.csvLines.toFile(inputFile)
      val colorFile = new File(Tool.searchCellLineDir, "pal1.txt")
      val command =
        s"""
           |${"Rscript"
            .condaPath()} ${Tool.rPath.unixPath}/cell_line_expr.R --i ${inputFile.unixPath} --c ${colorFile.unixPath} --order ${data.order} --l ${data.log}  --o ${pngFile.unixPath}
           |""".stripMargin
      val commandExec = CommandExec().exec { b =>
        CommandData(tmpDir, command)
      }
      val response = if (commandExec.isSuccess) {
        println("exec complete:", Utils.getTime(startTime))
        val base64 = pngFile.base64
        val geneData = new File(tmpDir, "gene.csv").str
        CellLineImage.Response(valid = true, base64 = base64, geneData = geneData)
      } else {
        CellLineImage.Response(valid = false, message = commandExec.errorInfo)
      }
      Tool.deleteDirectory(tmpDir)
      Ok(writeJs(response))
    }

  }

}
